Contract Functions
To send a transaction that executes a function of a contract on a blockchain, you can use a useContractFunction hook,
it works similarly to useSendTransaction. It returns a send
function that we can use to call a contract function and state
object.
To use useContractFunction
we need to supply it with a Contract of type Contract.
And a string functionName
.
send
function maps arguments 1 to 1 with functions of a contract and also accepts one additional argument of type TransactionOverrides.
Example
Start by declaring a contract variable with address of contract you want to call and ABI interface of a contract.
import { utils } from 'ethers'
import { Contract } from '@ethersproject/contracts'
...
const wethInterface = new utils.Interface(WethAbi)
const wethContractAddress = '0xA243FEB70BaCF6cD77431269e68135cf470051b4'
const contract = new Contract(wethContractAddress, wethInterface)
After that you can use the hook to create send
function and state
object.
const { state, send } = useContractFunction(contract, 'deposit', { transactionName: 'Wrap' })
const depositEther = (etherAmount: string) => {
send({ value: utils.parseEther(etherAmount) })
}
const { state, send } = useContractFunction(contract, 'withdraw', { transactionName: 'Unwrap' })
const withdrawEther = (wethAmount: string) => {
send(utils.parseEther(wethAmount))
}
The code snippets above will wrap and unwrap Ether into WETH using Wrapped Ether contract respectively.
Deposit function of a contract has no input arguments and instead wraps amount of ether sent to it. To send given amount of ether simply use a TransactionOverrides
object.
Withdraw function needs amount of ether to withdraw as a input argument.
You can add additional buffer of gas limit by setting gasLimitBufferPercentage
in config or directly in transaction options, see live example below.
It adds 10% of gas limit more to what is estimated by the Ethers library.
Live example
App will deposit 1 wei to Wrapped Ether contract. Connect a MetaMask wallet and switch to a test network, such as Kovan or Ropsten.
import React from 'react'
import ReactDOM from 'react-dom'
import { DAppProvider, useEthers, useContractFunction, Config, Goerli, Kovan, Rinkeby, Ropsten } from '@usedapp/core'
import { getDefaultProvider, utils } from 'ethers'
import { Contract } from '@ethersproject/contracts'
import { WethAbi, WETH_ADDRESSES } from './constants/Weth'
import { MetamaskConnect } from './components/MetamaskConnect'
const config: Config = {
readOnlyChainId: Goerli.chainId,
readOnlyUrls: {
[Goerli.chainId]: getDefaultProvider('goerli'),
[Kovan.chainId]: getDefaultProvider('kovan'),
[Rinkeby.chainId]: getDefaultProvider('rinkeby'),
[Ropsten.chainId]: getDefaultProvider('ropsten'),
},
}
ReactDOM.render(
<DAppProvider config={config}>
<App />
</DAppProvider>,
document.getElementById('root')
)
const WrapEtherComponent = (props: { chainId: number }) => {
const wethAddress = WETH_ADDRESSES[props.chainId]
const wethInterface = new utils.Interface(WethAbi)
const contract = new Contract(wethAddress, wethInterface) as any
const { state, send } = useContractFunction(contract, 'deposit', {
transactionName: 'Wrap',
gasLimitBufferPercentage: 10,
})
const { status } = state
const wrapEther = () => {
void send({ value: 1 })
}
return (
<div>
<button onClick={() => wrapEther()}>Wrap ether</button>
<p>Status: {status}</p>
</div>
)
}
export function App() {
const { account, chainId } = useEthers()
if (!config.readOnlyUrls[chainId]) {
return <p>Please use either Goerli, Kovan, Rinkeby or Ropsten testnet.</p>
}
return <div>{!account ? <MetamaskConnect /> : <WrapEtherComponent chainId={chainId} />}</div>
}